package com.aaaa.scheduler.pojo;

import com.aaaa.scheduler.scheduler.genetic.GeneticConfiguration;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.*;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Chromosome implements Comparable<Chromosome> {
    /**
     * 工序操作染色体
     */
    private int[] gene_OS;
    /**
     * 设备选择染色体
     */
    private int[] gene_MS;
    /**
     * 适应度值
     * TODO 后面可能扩展更复杂的适应度（多目标）
     */
    private double fitness;
    /**
     * 随机数
     */
    private Random r;


    //NSGA算法中染色体的参数

    /**
     * 该染色体所支配的染色体集合
     */
    private List<Chromosome> dominatedChromosomeList = new ArrayList<>();
    /**
     * 支配该染色体的染色体数量
     */
    private int dominationCount = 0;
    /**
     * 快速非支配排序后的等级
     */
    private int rank = 1;
    /**
     * 该染色体的拥挤度
     */
    private double crowdingDistance = 0;
    /**
     * 该染色体所有目标值   需要转化一下（比如取倒数），使得值越小染色体越优
     */
    private List<Double> objectiveFitnessValueList = new ArrayList<>();

    /**
     * 到最近的参考点直线的距离
     */
    private double dMin = Double.MAX_VALUE;
    /**
     * 该染色体所有目标值   需要转化一下（比如取倒数），使得值越小染色体越优
     */
    private List<Double> normalizeObjectiveValueList = new ArrayList<>();



    public Chromosome(Random r){
        this.r = r;
    }

    public Chromosome(Instance instance, Random r) {
        this.r = r;
        instance.setChromosomeCreateName("随机生成染色体");
        ArrayList<Integer> os = new ArrayList<>();
        for (Process process : instance.getProcessMap().values()) {
            os.add(process.getProductID());//把工单的所有工序加入染色体
        }
        Collections.shuffle(os);//打乱顺序

        ArrayList<Integer> ms = new ArrayList<>();
        List<Product> productList = new ArrayList<>(instance.getProductMap().values());//把instance里的工件map取出到list，按照ID进行排序
        Collections.sort(productList, (o1, o2) -> {
            return o1.getID() - o2.getID();
        });
        for (Product product : productList) {
            List<Process> opList = product.getOpList();
            for (Process process : opList) {
                int canMachineNum = process.getCandidateProNum();
                int a = new Random().nextInt(canMachineNum) + 1;
                ms.add(a);//给每个工件的每道工序分配一台设备，这个数字代表可生产设备中的第几台
            }
        }

        this.gene_OS = new int[os.size()];
        for(int i = 0; i < os.size(); i++) {
            this.gene_OS[i] = os.get(i);
        }
        this.gene_MS = new int[ms.size()];
        for(int i = 0; i < ms.size(); i++) {
            this.gene_MS[i] = ms.get(i);
        }

//        this.fitness = 0;
        for (int i = 0; i < GeneticConfiguration.objectiveList.size(); i++) {
            this.objectiveFitnessValueList.add(0.0);
            this.normalizeObjectiveValueList.add(0.0);
        }
    }

    public Chromosome(int[] OS,int[] MS) {
        this.gene_OS = OS;
        this.gene_MS = MS;
//        this.fitness = -1;
        for (int i = 0; i < GeneticConfiguration.objectiveList.size(); i++) {
            this.objectiveFitnessValueList.add(-1.0);
            this.normalizeObjectiveValueList.add(-1.0);
        }
    }

    public Chromosome(Chromosome c) {
        this.gene_MS = new int[c.gene_MS.length];
        System.arraycopy(c.gene_MS, 0, this.gene_MS, 0, c.gene_MS.length);
        this.gene_OS = new int[c.gene_OS.length];
        System.arraycopy(c.gene_OS, 0, this.gene_OS, 0, c.gene_OS.length);
//        this.fitness = c.fitness;
        this.objectiveFitnessValueList.addAll(c.getObjectiveFitnessValueList());
        this.normalizeObjectiveValueList.addAll(c.getNormalizeObjectiveValueList());
    }

    /**
     * 功能描述：清空和快速非支配排序相关的属性
     *
     */
    public void reset() {
        this.dominationCount = 0;
        this.rank = Integer.MAX_VALUE;
        this.dominatedChromosomeList = new ArrayList<>();
    }

    @Override
    public int compareTo(Chromosome o) {
        if(o.objectiveFitnessValueList.get(0).equals(this.objectiveFitnessValueList.get(0)) && this.getObjectiveFitnessValueList().size()>1){
            return Double.compare(this.objectiveFitnessValueList.get(1), o.objectiveFitnessValueList.get(1));
        }
        return Double.compare(this.objectiveFitnessValueList.get(0), o.objectiveFitnessValueList.get(0));
    }
}
